namespace SimpleWebServices.Models
{
    using System;
    using System.Collections.ObjectModel;
    using System.Web;
    using System.Xml.XPath;
    using Moq;
    using SimpleWebServices;
    using SimpleWebServices.Configuration;
    using SimpleWebServices.Data;
    using SimpleWebServices.Security.Cryptography;
    using SimpleWebServices.Web;
    using SimpleWebServices.Web.UI.Html;
    using SimpleWebServices.Web.UI.Html.Elements;
    using Xunit;

    public sealed class TenantFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<Tenant>()
                .DerivesFrom<SimpleWebServices.Data.Record>()
                .IsConcreteClass()
                .IsUnsealed()
                .HasDefaultConstructor()
                .XmlRoot("tenant")
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            Tenant actual = (
                "<tenant name='Default'>" +
                    "<favicons>" +
                        "<favicon rel='icon' type='image/x-icon' href='http://static.example.com/-/favicon.ico' />" +
                    "</favicons>" +
                    "<elements>" +
                        "<div id='top'>" +
                            "<ul id='tabs'>" +
                                "<li id='tab.home' class='tab'>Home</li>" +
                            "</ul>" +
                        "</div>" +
                    "</elements>" +
                    "<master-pages>" +
                        "<value name='html'>HtmlRepresentation.Default</value>" +
                        "<value name='xhtml'>XhtmlRepresentation.Default</value>" +
                    "</master-pages>" +
                    "<stylesheets>" +
                        "<stylesheet media='screen' />" +
                        "<stylesheet media='print'>" +
                            "<import>http://static.example.com/-/print.css</import>" +
                        "</stylesheet>" +
                    "</stylesheets>" +
                "</tenant>").Deserialize<Tenant>();

            Assert.Equal<string>("icon", actual.Favicons[0].Relationship);
            Assert.Equal<string>("image/x-icon", actual.Favicons[0].Type);
            Assert.Equal<string>("http://static.example.com/-/favicon.ico", actual.Favicons[0].Href);

            Assert.Equal<string>("tab", actual.Elements["tab.home"].Class);

            Assert.Equal<int>(2, actual.MasterPages.Count);
            Assert.Equal<string>("HtmlRepresentation.Default", actual.MasterPages["html"]);
            Assert.Equal<string>("XhtmlRepresentation.Default", actual.MasterPages["xhtml"]);

            Assert.Equal<string>("Default", actual.Name);

            Assert.Equal<string>("http://static.example.com/-/print.css", actual.StyleSheets[1].Imports[0]);
        }

        [Fact]
        public void deserializeEmpty()
        {
            Tenant actual = "<tenant />".Deserialize<Tenant>();

            Assert.Null(actual.Name);
            Assert.Empty(actual.Favicons);
            Assert.Empty(actual.Elements);
            Assert.Empty(actual.MasterPages);
            Assert.Empty(actual.StyleSheets);
        }

        [Fact]
        public void serialize()
        {
            Tenant obj = new Tenant
            {
                Name = "Default",
                MasterPages = new DataCollection
                {
                    { "html", "HtmlRepresentation.Default" },
                    { "xhtml", "XhtmlRepresentation.Default" }
                }
            };

            obj.Favicons.Add("<favicon rel='icon' type='image/x-icon' href='http://static.example.com/-/favicon.ico' />".Deserialize<Favicon>());
            obj.Elements.Add((
                "<img" +
                    " id='logo'" +
                    " class='class'" +
                    " lang='fr'" +
                    " title='title'" +
                    " alt='alternative'" +
                    " height='100'" +
                    " longdesc='http://example.com/longdesc'" +
                    " src='http://example.com/source' width='200'" +
                    " />").Deserialize<Image>());
            obj.StyleSheets.Add("<stylesheet media='screen'><import>http://static.example.com/-/screen1.css</import></stylesheet>".Deserialize<StyleSheet>());

            XPathNavigator navigator = obj.Serialize().CreateNavigator();

            Assert.True((bool)navigator.Evaluate("1=count(/tenant[@name='Default']/favicons/favicon[@rel='icon'][@type='image/x-icon'][@href='http://static.example.com/-/favicon.ico'])"));

            Assert.True((bool)navigator.Evaluate("1=count(/tenant[@name='Default']/elements/img[@id='logo'][@class='class'][@lang='fr'][@title='title'][@alt='alternative'][@height='100'][@longdesc='http://example.com/longdesc'][@src='http://example.com/source'][@width='200'])"));

            Assert.True((bool)navigator.Evaluate("2=count(/tenant[@name='Default']/master-pages/value)"));
            Assert.True((bool)navigator.Evaluate("1=count(/tenant[@name='Default']/master-pages/value[@name='html'][text()='HtmlRepresentation.Default'])"));
            Assert.True((bool)navigator.Evaluate("1=count(/tenant[@name='Default']/master-pages/value[@name='xhtml'][text()='XhtmlRepresentation.Default'])"));

            Assert.True((bool)navigator.Evaluate("1=count(/tenant[@name='Default']/stylesheets/stylesheet[@media='screen']/import[text()='http://static.example.com/-/screen1.css'])"));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new Tenant());
        }

        [Fact]
        public void prop_Current()
        {
            FakeRepository.Clear();

            try
            {
                FakeRepository.Register<Tenant>(new
                {
                    urn = "urn://example.com/tenant/sample",
                    xml = "<tenant name='Sample' />"
                });

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.Path).Returns("/sample").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                string expected = "Sample";
                string actual = Tenant.Current.Name;

                Assert.Equal<string>(expected, actual);

                mock.VerifyAll();
            }
            finally
            {
                FakeRepository.Reset();
                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void prop_Current_whenNotFound()
        {
            FakeRepository.Clear();

            try
            {
                FakeRepository.Register<Tenant>(new
                {
                    urn = "urn://example.com/tenant/-",
                    xml = "<tenant name='Default' />"
                });

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.Path).Returns("/sample").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                Assert.Null(Tenant.Current);

                mock.VerifyAll();
            }
            finally
            {
                FakeRepository.Reset();
                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void prop_Elements()
        {
            Assert.True(new PropertyExpectations(typeof(Tenant).GetProperty("Elements"))
                .XmlElement("elements")
                .TypeIs<ElementCollection>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Entity()
        {
            Assert.True(new PropertyExpectations(typeof(Tenant).GetProperty("Entity"))
                .XmlIgnore()
                .TypeIs<string>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Entity_get()
        {
            Tenant obj = (
                "<tenant name='Default'>" +
                    "<favicons>" +
                        "<favicon rel='icon' type='image/x-icon' href='http://static.example.com/-/favicon.ico' />" +
                    "</favicons>" +
                    "<stylesheets>" +
                        "<stylesheet media='screen'>" +
                            "<import>http://static.example.com/-/screen1.css</import>" +
                            "<import>http://static.example.com/-/screen2.css</import>" +
                        "</stylesheet>" +
                        "<stylesheet media='print'>" +
                            "<import>http://static.example.com/-/print1.css</import>" +
                            "<import>http://static.example.com/-/print2.css</import>" +
                        "</stylesheet>" +
                    "</stylesheets>" +
                "</tenant>").Deserialize<Tenant>();

            string expected = "NTsKogB5whPqoMLEG/RciA==";
            string actual = MD5Hash.Compute(obj.Entity);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Entity_getEmpty()
        {
            string expected = string.Empty;
            string actual = new Tenant().Entity;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Favicons()
        {
            Assert.True(new PropertyExpectations(typeof(Tenant).GetProperty("Favicons"))
                .XmlArray("favicons", "favicon")
                .TypeIs<Collection<Favicon>>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_MasterPages()
        {
            Assert.True(new PropertyExpectations(typeof(Tenant).GetProperty("MasterPages"))
                .XmlElement("master-pages")
                .TypeIs<DataCollection>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Name()
        {
            Assert.True(new PropertyExpectations(typeof(Tenant).GetProperty("Name"))
                .XmlAttribute("name")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_StyleSheets()
        {
            Assert.True(new PropertyExpectations(typeof(Tenant).GetProperty("StyleSheets"))
                .XmlArray("stylesheets", "stylesheet")
                .TypeIs<Collection<StyleSheet>>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void op_GetCurrentOfT()
        {
            FakeRepository.Clear();

            try
            {
                FakeRepository.Register<Tenant>(new
                {
                    urn = "urn://example.com/tenant/sample",
                    xml = "<tenant name='Sample' />"
                });

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.Path).Returns("/sample").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                string expected = "Sample";
                string actual = Tenant.GetCurrent<Tenant>().Name;

                Assert.Equal<string>(expected, actual);

                mock.VerifyAll();
            }
            finally
            {
                FakeRepository.Reset();
                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_Format_stringName()
        {
            FakeRepository.Clear();

            try
            {
                FakeRepository.Register<Tenant>(new
                {
                    urn = "urn://example.com/tenant/sample",
                    xml = "<tenant name='Sample' />"
                });

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.Path).Returns("/sample").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                string expected = "Sample";
                string actual = Tenant.Format("{tenant-name}");

                Assert.Equal<string>(expected, actual);

                mock.VerifyAll();
            }
            finally
            {
                FakeRepository.Reset();
                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_Format_stringPath()
        {
            FakeRepository.Clear();

            try
            {
                FakeRepository.Register<Tenant>(new
                {
                    urn = "urn://example.com/tenant/sample",
                    xml = "<tenant />"
                });

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.Path).Returns("/sample").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                string expected = "/sample";
                string actual = Tenant.Format("{tenant-path}");

                Assert.Equal<string>(expected, actual);

                mock.VerifyAll();
            }
            finally
            {
                FakeRepository.Reset();
                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_Format_stringEmpty()
        {
            string expected = string.Empty;
            string actual = Tenant.Format(expected);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_Format_stringNull()
        {
            Assert.Null(Tenant.Format(null as string));
        }

        [Fact]
        public void op_HtmlAttributeEncode_string()
        {
            FakeRepository.Clear();

            try
            {
                FakeRepository.Register<Tenant>(new
                {
                    urn = "urn://example.com/tenant/sample",
                    xml = "<tenant name='Sample' />"
                });

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.Path).Returns("/sample").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                string expected = "&quot;Sample&quot;";
                string actual = Tenant.HtmlAttributeEncode("\"{tenant-name}\"");

                Assert.Equal<string>(expected, actual);

                mock.VerifyAll();
            }
            finally
            {
                FakeRepository.Reset();
                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_HtmlAttributeEncode_stringEmpty()
        {
            string expected = string.Empty;
            string actual = Tenant.HtmlAttributeEncode(expected);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_HtmlAttributeEncode_stringNull()
        {
            Assert.Null(Tenant.HtmlAttributeEncode(null as string));
        }

        [Fact]
        public void op_HtmlEncode_string()
        {
            FakeRepository.Clear();

            try
            {
                FakeRepository.Register<Tenant>(new
                {
                    urn = "urn://example.com/tenant/sample",
                    xml = "<tenant name='Sample' />"
                });

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.Path).Returns("/sample").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                string expected = "&quot;Sample&quot;";
                string actual = Tenant.HtmlEncode("\"{tenant-name}\"");

                Assert.Equal<string>(expected, actual);

                mock.VerifyAll();
            }
            finally
            {
                FakeRepository.Reset();
                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_HtmlEncode_stringApostrophe()
        {
            FakeRepository.Clear();

            try
            {
                FakeRepository.Register<Tenant>(new
                {
                    urn = "urn://example.com/tenant/sample",
                    xml = "<tenant />"
                });

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.Path).Returns("/sample").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                string expected = "It&apos;s";
                string actual = Tenant.HtmlEncode("It's");

                Assert.Equal<string>(expected, actual);

                mock.VerifyAll();
            }
            finally
            {
                FakeRepository.Reset();
                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_HtmlEncode_stringEmpty()
        {
            string expected = string.Empty;
            string actual = Tenant.HtmlEncode(expected);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_HtmlEncode_stringNull()
        {
            Assert.Null(Tenant.HtmlEncode(null as string));
        }

        [Fact]
        public void op_UrlPathEncode_string()
        {
            FakeRepository.Clear();

            try
            {
                FakeRepository.Register<Tenant>(new
                {
                    urn = "urn://example.com/tenant/-",
                    xml = "<tenant />"
                });

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.Path).Returns("/-/sample").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                string expected = "/-";
                string actual = Tenant.UrlPathEncode("{tenant-path}");

                Assert.Equal<string>(expected, actual);

                mock.VerifyAll();
            }
            finally
            {
                FakeRepository.Reset();
                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_UrlPathEncode_stringEmpty()
        {
            string expected = string.Empty;
            string actual = Tenant.UrlPathEncode(expected);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_UrlPathEncode_stringNull()
        {
            Assert.Null(Tenant.UrlPathEncode(null as string));
        }
    }
}